////////////////////////////////////////////////////////////////////
// Programme de dump des fichiers de Chrono Cross
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// Nemesis pour Terminus Traduction (tt_nemesis@yahoo.fr)
// Date de création :		29/07/03
// Dernière modification :	31/07/03
////////////////////////////////////////////////////////////////////

// Entete
#include "Dump.h"

// Type de données pour les Rooms
typedef struct {
	char *nom;
	unsigned _int32 adr;
	unsigned _int8 fin;
} Dump_TRoom;

// Noms des fichiers
Dump_TRoom Dump_Rooms[DUMP_ROOMS_NB];
// Nombres de fichiers
_int16 Dump_Rooms_Nb;

// Secteurs des adresses de fichiers
_int32 Dump_Secteur_Entete=0;

/*------------------------------------------------------------------
  Initialisation du Dump de fichiers
------------------------------------------------------------------*/
void Dump_Initialisation (void)
{
	// Fichier des infos
	FILE *infos_f;
	// Nom de l'iso (chemin)
	char infos_nom[DUMP_NOM_MAX];
	// Numero de fichier
	int room_deb,room_fin,r;
	// Nom de fichier
	char room_nom_complet[DUMP_ROOMS_NOM];
	char room_nom[DUMP_ROOMS_NOM];
	char room_ext[4];
	// Ligne
	char ligne[DUMP_LIGNE_MAX];
	// Nombre de champs d'infos
	int result;

	Main_Message_S("Initialisation du dump... ","",OK);
	// Ouverture du fichier des infos principales
	sprintf(infos_nom,"%s%s.%s",DIR_INFOS,INFOS_FICH,EXT_INFOS);
	infos_f=fopen(infos_nom,"rb");

	if (infos_f==NULL)
		Main_Message_S("Erreur d'ouverture.\n","",ER);
	else {
		// Operations non protegées
		// Récupération du secteur des pointeurs
		fscanf(infos_f,"%d",&Dump_Secteur_Entete);
		// Récupération du nombre de fichiers
		fscanf(infos_f,"%d",&Dump_Rooms_Nb);
		// Passage à la ligne suivante
		fgets(ligne,DUMP_LIGNE_MAX,infos_f);
		// Récupération des noms de fichiers
		while (fgets(ligne,DUMP_LIGNE_MAX,infos_f)!=NULL)
			// Cas d'un commentaire ou d'un blanc
			if (ligne[0]!=COMMENT) {
				result=sscanf(ligne,"%d-%d %3s %s",
					&room_deb,&room_fin,room_ext,room_nom);
				switch (result) {
				case 4:
					sprintf(room_nom_complet,
						" (%s).%s",room_nom,room_ext);
					break;
				case 3:
					sprintf(room_nom_complet,
						".%s",room_ext);
					break;
				case 2:
					sprintf(room_nom_complet,
						".%s",EXT_DUMP);
					break;
				default:
					Main_Message_S("Info erronee... ","",ER);
				}
				if (result>1)
					for(r=room_deb;r<=room_fin;r++)
						Dump_Rooms[r].nom=strdup(room_nom_complet);
			}
		// Fermeture du fichier des infos
		fclose(infos_f);
	}
	Main_OK();
}

/*------------------------------------------------------------------
  Dump de l'entete de l'iso se finissant en Dump_Secteur_Entete
------------------------------------------------------------------*/
void Dump_Entete (void)
{
	// Index de secteur
	unsigned _int32 s;
	// Fichier entete
	FILE *entete_f;
	// Nom du fichier (chemin)
	char entete_nom[DUMP_NOM_MAX];

	Main_Message_S("Dump de l'entete de l'image... ","",OK);
	// Ouverture du fichier entete
	sprintf(entete_nom,"%s%s.%s",DIR_DUMP_IN,FICH_ENTETE,EXT_DUMP);
	entete_f=fopen(entete_nom,"wb");

	if (entete_f==NULL)
		Main_Message_S("Impossible d'ecrire l'entete.\n","",ER);
	else {
		// Placement en début d'image
		Iso_Secteur_Saut(0);
		// Recopie des premiers secteurs
		for(s=0;s<Dump_Rooms[0].adr;s++)
			Iso_Secteur_Extrait(entete_f);
	}

	Main_OK();
}

/*------------------------------------------------------------------
  Dump des infos de ficheirs pointés par Dump_Secteur_Entete
------------------------------------------------------------------*/
void Dump_Pointeurs (void)
{
	// Numero de pointeur
	_int16 ptr=0;
	_int16 p;
	// Lecture de l'adresse avant traitement
	unsigned _int32 buffer[SECTEUR_DONNEES/4];

	Main_Message_S("Dump des informations des fichiers... ","",OK);
	// Placement sur la table d'adresses
	Iso_Secteur_Saut(Dump_Secteur_Entete);
	while(ptr<Dump_Rooms_Nb) {
		// Changement de secteur
		Iso_Entete_Lit(NON);
		Iso_Adresses_Lit(buffer);
		// Traitement des adresses
		for(p=0;p<(SECTEUR_DONNEES/4);p++)
			// Test du bit de poids fort du 2ème octet (0=ok)
			if (!(buffer[p] & 0x00800000)) {
				Dump_Rooms[ptr].fin=(unsigned _int8)(buffer[p]>>24);
				Dump_Rooms[ptr].adr=(buffer[p]<<8)>>8;
				ptr++;
			}
		Iso_ECC_Saut();
	};
	Main_OK();
}

/*------------------------------------------------------------------
  Dump d'un fichier avec secteurs intégraux
  la fonction assume que l'iso est déjà ouverte en lecture
--------------------------------------------------------------------
 <- room_num = fichier en question déterminé par son numéro
	dans la table des fichiers
------------------------------------------------------------------*/
void Dump_Full (unsigned _int16 room_num)
{
	// Fichier Room de sortie
	FILE *room_f;
	// Nom du fichier (chemin)
	char room_nom[DUMP_NOM_MAX];
	// Numero de secteur
	int sec;

	// Test du paramètre
	if (room_num<0 || room_num>Dump_Rooms_Nb)
		Main_Message_D("Room %d inexistante.\n",room_num,ER);
	else {
		// Evaluation du nom de fichier
		if (Dump_Rooms[room_num].nom==NULL)
			sprintf(room_nom,"%s%04d.%s",
				DIR_DUMP_IN,room_num,EXT_DUMP);
		else
			sprintf(room_nom,"%s%04d%s",DIR_DUMP_IN,room_num,
				Dump_Rooms[room_num].nom);
		// Ouverture du fichier room
		room_f=fopen(room_nom,"wb");

		if (room_f==NULL)
			Main_Message_S("Impossible d'ecrire le fichier.\n","",ER);
		else {
			// Début du fichier
			sec=Dump_Rooms[room_num].adr;
			// Parcours du fichier
			do {
				// Placement en début de secteur
				Iso_Secteur_Saut(sec);
				Iso_Secteur_Extrait(room_f);
				sec++;
			} while (Iso_Entete_Lit(NON)!=SECT_TFIN);
			fclose(room_f);
		}
	}
}

/*------------------------------------------------------------------
  Dump d'un fichier (appelé par Dump_Exec)
  la fonction assume que l'iso est déjà ouverte en lecture
--------------------------------------------------------------------
 <- room_num = fichier en question déterminé par son numéro
	dans la table des fichiers
------------------------------------------------------------------*/
void Dump_Room (unsigned _int16 room_num)
{
	// Fichier Room de sortie
	FILE *room_f;
	// Nom du fichier (chemin)
	char room_nom[DUMP_NOM_MAX];

	// Test du paramètre
	if (room_num<0 || room_num>Dump_Rooms_Nb)
		Main_Message_D("Room %d inexistante.\n",room_num,ER);
	else {
		// Evaluation du nom de fichier
		if (Dump_Rooms[room_num].nom==NULL)
			sprintf(room_nom,"%s%04d.%s",
				DIR_DUMP_IN,room_num,EXT_DUMP);
		else
			sprintf(room_nom,"%s%04d%s",DIR_DUMP_IN,room_num,
				Dump_Rooms[room_num].nom);
		// Ouverture du fichier room
		room_f=fopen(room_nom,"wb");

		if (room_f==NULL)
			Main_Message_S("Impossible d'ecrire le fichier.\n","",ER);
		else {
			// Placement en début de fichier
			Iso_Secteur_Saut(Dump_Rooms[room_num].adr);
			// Parcours du fichier
			while (Iso_Entete_Lit(NON)!=SECT_TFIN) {
				Iso_Donnees_Extrait(room_f,0);
				Iso_ECC_Saut();
			}
			Iso_Donnees_Extrait(room_f,Dump_Rooms[room_num].fin);
			fclose(room_f);
		}
	}
}

/*------------------------------------------------------------------
  Dump d'un ensemble de fichiers
--------------------------------------------------------------------
 <- rooms = ensemble des fichiers déterminés par des délimiteurs
	exemple : 1-4;5;8 = fichiers 1->5 + 8
------------------------------------------------------------------*/
void Dump_Exec (char* rooms)
{
	// Numéros des Rooms à extraire
	char* room_intervals[DUMP_ROOMS_INTER];
	char *room_interval;
	int interval,i;
	// Type d'intervalle
	int result;
	// Bornes
	unsigned _int16 room_deb,room_fin,r;
	// Fonction à appeler
	void (*fonc)(unsigned _int16);

	Main_Message_S("Dump des fichiers %s en cours... ",rooms,OK);

	// Décomposition des rooms en intervalles
	interval=0; // intervalle actuel
	room_intervals[interval]=strtok(rooms,";");
	do
		interval++;
	while((room_intervals[interval]=strtok(NULL,";"))!=NULL);

	// Extension des intervalles
	for(i=0;i<interval;i++) {
		// Test de dump intégral
		if (room_intervals[i][0]==DUMP_INTEGRAL) {
			room_interval=&room_intervals[i][1];
			fonc = Dump_Full;
		} else {
			room_interval=room_intervals[i];
			fonc = Dump_Room;
		}
		result=sscanf(room_interval,"%d-%d",
			&room_deb,&room_fin);
		switch (result) {
		case 1:
			fonc(room_deb);
			break;
		case 2:
			for (r=room_deb;r<=room_fin;r++)
				fonc(r);
			break;
		default:
			Main_Message_D("Erreur dans l'intervalle %d.\n",i+1,ER);
		}
	}
	Main_OK();
}

/*------------------------------------------------------------------
  Suppression d'un fichier (appelé par Supprime_Exec)
--------------------------------------------------------------------
 <- room_num = fichier en question déterminé par son numéro
	dans la table des fichiers
------------------------------------------------------------------*/
void Dump_Sup_Room (unsigned _int16 room_num)
{
	// Nom du fichier (chemin)
	char room_nom[DUMP_NOM_MAX];

	// Recherche du fichier
	struct _finddata_t c_file;
    long hFile;

	sprintf(room_nom,"%s%04d*.*",DIR_DUMP_IN,room_num);
	hFile = _findfirst(room_nom, &c_file );
	do {
		sprintf(room_nom,"%s%s",DIR_DUMP_IN,c_file.name);
		remove(room_nom);
    } while(_findnext(hFile,&c_file)==0);
	_findclose(hFile);
}

/*------------------------------------------------------------------
  Nettoyage d'un ensemble de fichiers
--------------------------------------------------------------------
 <- rooms = ensemble des fichiers déterminés par des délimiteurs
	exemple : 1-4;5;8 = fichiers 1->5 + 8
------------------------------------------------------------------*/
void Dump_Sup_Exec (char* rooms)
{
	// Numéros des Rooms à extraire
	char* room_intervals[DUMP_ROOMS_INTER];
	int interval,i;
	// Type d'intervalle
	int result;
	// Bornes
	unsigned _int16 room_deb,room_fin,r;

	Main_Message_S("Suppression de %s en cours... ",rooms,OK);

	// Décomposition des rooms en intervalles
	interval=0; // intervalle actuel
	room_intervals[interval]=strtok(rooms,";");
	do
		interval++;
	while((room_intervals[interval]=strtok(NULL,";"))!=NULL);

	// Extension des intervalles
	for(i=0;i<interval;i++) {
		result=sscanf(room_intervals[i],"%d-%d",
			&room_deb,&room_fin);
		switch (result) {
		case 1:
			Dump_Sup_Room(room_deb);
			break;
		case 2:
			for (r=room_deb;r<=room_fin;r++)
				Dump_Sup_Room(r);
			break;
		default:
			Main_Message_D("Erreur dans l'intervalle %d.\n",i+1,ER);
		}
	}
	Main_OK();
}